;int descomprimir buffer ( unsigned char *src buf,
;unsigned int long codificacion, unsigned char *dst buf,
;unsigned int dst size, codigo t *tabla codigos )
;  • Descripci ́n: Dado un buffer y una tabla de c ́digos realiza la decodificaci ́n y
;    pone el resultado en el buffer de salida.
;  • Funciones auxiliares que utiliza: cargar arbol huffman.


global descomprimir_buffer
extern cargar_arbol_huffman
extern free
extern printf

%define p_src_buf ebp+8
%define long_codificacion ebp+12
%define p_dst_buf ebp+16
%define dst_size ebp+20
%define p_tabla_codigos ebp+24

%define cod_error ebp-4
%define p_arbol ebp-8
%define ptr_actual_src ebp-12
%define ptr_actual_dst ebp-16

%define null 0
%define cod_ok_descomprimir 0
%define cod_not_ok_descomprimir -1


%define offset_simbolo 0
%define offset_apariciones 1
%define offset_valido 5
%define offset_p_padre	9 
%define offset_p_izq	13
%define offset_p_der	17

%define valido 1
%define invalido 0

section .data
msg_error_tabla_codigos_null: 	db	'ERROR: La tabla de codigos se recibio null',10,0
msg_error_cargar_arbol:		db	'ERROR: No se pudo cargar el arbol de huffman', 10,0
msg_error_src_null:		db	'ERROR: El buffer src no puede ser null',10,0
msg_error_dst_null:		db	'ERROR: El buffer dst no puede ser null',10,0
msg_error_al_descomprimir:	db	'ERROR: Error grave al descomprimir',10,0
msg_error_desborde:		db	'ERROR: Se produjo desborde al descomprimir',10,0

section .text
descomprimir_buffer:

	push ebp
	mov ebp,esp
	sub esp,16
	push ebx
	push esi
	push edi
	
	mov dword [p_arbol], null		; inicializamor el ptr al arbol
	mov dword [cod_error], cod_ok_descomprimir  ;suponemos que todo empieza bien.
	
	mov edi, [p_tabla_codigos]	; en edi tenemos la tabla de codigos
	cmp edi,null
	jne _tabla_codigos_ok
	
	push dword msg_error_tabla_codigos_null
	call printf
	add esp,4
	
	mov dword [cod_error], cod_not_ok_descomprimir
	jmp _liberar_recursos_descomprimir
	
_tabla_codigos_ok:
	
	lea esi, [p_arbol]
	push esi
	push edi
	call cargar_arbol_huffman
	add esp,8

	mov edi, [p_arbol]
	cmp edi, null
	jne _arbol_cargado_ok
	
	push dword msg_error_cargar_arbol
	call printf
	add esp,4
	
	mov dword [cod_error], cod_not_ok_descomprimir
	jmp _liberar_recursos_descomprimir
	
_arbol_cargado_ok:

	; Primero chequeamos si los buffers son nulos
	 
	cmp dword [p_src_buf], null
	jne _buffer_src_ok
	 
	push dword msg_error_src_null
	call printf
	add esp,4
	 
	mov dword [cod_error], cod_not_ok_descomprimir
	jmp _liberar_recursos_descomprimir
	 
_buffer_src_ok:
	 
	cmp dword [p_dst_buf], null
	jne _buffer_dst_ok
	 
	push dword msg_error_dst_null
	call printf
	add esp,4
	 
	mov dword [cod_error], cod_not_ok_descomprimir
	jmp _liberar_recursos_descomprimir
	 
_buffer_dst_ok:
	 
	; edi <-- cantidad de bits que restan descomprimir
	; eax <-- cantidad de bits utilizados en la primer porcion de 32 bits
	; ptr_actual_src <-- ptr a los 4 bytes tratados actualmente del buffer src
	; ptr_actual_dst <-- ptr al byte actual
	
	mov edi, [long_codificacion]
	mov eax, [p_src_buf]
	mov [ptr_actual_src], eax
	mov ebx, [eax]			; inicializamos ebx para la primer vez que entra al ciclo.
	bswap ebx
	mov eax, [p_dst_buf]
	mov [ptr_actual_dst], eax
	xor eax, eax
	xor ecx, ecx

	mov esi, [p_arbol]
	
_ciclo_decodificacion:

	cmp edi, 0
	ja _quedan_bits				; si es mayor unsigned quedan bits
	jne _error_codificacion			; si es igual es porque terminamos
						; si es menor unsigned
	jmp _volcar_ultimo_byte			; ei es igual nos resta un byte por volcar.	
	
_error_codificacion:
	push dword msg_error_al_descomprimir
	call printf
	add esp,4
	
	mov dword [cod_error], cod_not_ok_descomprimir
	jmp _liberar_recursos_descomprimir
	
_quedan_bits:	


	cmp ecx, 0   ; ecx solo es 0 la primera vez que entramos al ciclo.
		     ; esto es porque no existen los codigos de 0 bits
	je _ciclo_busca_codigo 
	
	
	add eax, ecx
	cmp eax, 32	
	jl _seguimos_en_el_mismo_dd
	add dword [ptr_actual_src],4 ; apuntamos al sig. bloque de 32 bits
	sub eax, 32		; en eax lo que esta gastado del nuevo.
	
	
_seguimos_en_el_mismo_dd:


	mov esi, [ptr_actual_dst]
	mov [esi], dl		; escribimos el byte en el resultado	
	inc dword [ptr_actual_dst]   ; apuntamos al sig. byte a escribir en el sig. paso.
	
	mov esi, [ptr_actual_src]

	mov ebx, [esi]
	bswap ebx
	
	mov ecx, eax
	shl ebx, cl
	
	mov esi, [esi+4]
	bswap esi

	mov ecx, 32
	sub ecx, eax
	
	cmp ecx, 32
	jne _shr_valido
	; si ecx es 32 como intel solo permite hasta el 31, le aplica máscara y no nos sive porque lo toma como 0
	; shr simulado de 32, deja en 0 el registro.
_shr_simulado:
	xor esi,esi
	jmp _aplicar_mascara
_shr_valido:
	shr esi, cl
_aplicar_mascara:
	or ebx, esi		; en ebx ya tenemos los primeros 32 bits sin codificar
	
	mov esi, [p_arbol]


_ciclo_busca_codigo:	
	

; entrada de _ciclo_busca_codigo
; ebx <- primeros 32 bits sin decodificar.
; esi <- ptr al arbol arbol

;-------- Invariante del ciclo: --------------------------
;ebx <--  En la parte mas significativa tiene los primeros 32 - ecx bits sin decodificar
;ecx <--  Número de bits gastados hasta el momento, coincide con los shl realizados a ebx.
;esi <--  Ptr al arbol actual (esi va descendiendo por izq o derecha dependiendo del carry del shl)
;---------------------------------------------------------

	xor ecx,ecx		; ponemos en 0 el registro
	
_buscar_siguiente:

	inc ecx			; gastamos un bit.
	cmp dword [esi+offset_valido], valido
	jne _buscar_hijo_correcto
	xor edx,edx
	mov dl, [esi+offset_simbolo]	; como encontramos el nodo valido devolvemos el simbolo.
	
	; Comprobamos si el nodo es el padre => caso 1 solo codigo y sin nodo extra, no hay que restar 1 a la altura.
	cmp dword [esi+offset_p_padre], null
	je _comprobar_desborde
	
	dec ecx	      ; decrementamos ecx en 1 porque es la altura del arbol y no la long. del codigo.
	
_comprobar_desborde:

	cmp edi, ecx
	jae _no_hubo_desborde
	
	jmp _hubo_desborde
	
_no_hubo_desborde:

	sub edi, ecx  ; actualizamos el nro de bits que quedarían.
	jmp _ciclo_decodificacion
	
_buscar_hijo_correcto:

	shl ebx,1
	jc _prox_hijo_derecho
	mov esi, [esi+offset_p_izq]	; esi <-- hijo_izquierdo(esi)
	jmp _ver_si_hijo_es_nulo
	
_prox_hijo_derecho:
	mov esi, [esi+offset_p_der]	; esi <-- hijo_derecho(esi)
	
_ver_si_hijo_es_nulo:
	cmp esi, null			; para no romper el invariante, verificamos aqui.
	je _un_sub_arbol_estaba_null
	
	jmp _buscar_siguiente


; salida de _ciclo_busca_codigo
;esi <-- no null =>
;	ecx <-- cantidad de bits gastados en el último código
;	dl <-- simbolo obtenido.
;esi <-- null =>
;	no se encontro el simbolo.  (Se da solo por error por sub-arbol nulo)

_un_sub_arbol_estaba_null:
	
	push dword msg_error_al_descomprimir
	call printf
	add esp,4
	mov dword [cod_error], cod_not_ok_descomprimir
	jmp _liberar_recursos_descomprimir
	
_volcar_ultimo_byte:
	; Ver si es en todos los casos o cuando entra justo no !!!
	mov esi, [ptr_actual_dst]
	mov [esi], dl		; escribimos el byte en el resultado	
	jmp _liberar_recursos_descomprimir

_hubo_desborde:	

	push dword msg_error_desborde
	call printf
	add esp,4
	mov dword [cod_error], cod_not_ok_descomprimir

_liberar_recursos_descomprimir:
	mov eax, [p_arbol]
	cmp eax, null
	je fin
	
	push eax
	call _liberar_arbol
	add esp,4
	
fin:
	mov eax, [cod_error]		; seteamos el codigo de error
	
	pop edi
	pop esi
	pop ebx
	leave
	ret


	
; funcion recursiva (ojo)
;void liberar_arbol(nodo_arbol_t *arbol);
%define p_arbol_lib ebp+8
%define null 0
%define offset_izq 13
%define offset_der 17
_liberar_arbol:
	push ebp
	mov ebp,esp
	push ebx
	push esi
	push edi

	mov ebx, [p_arbol_lib]
	cmp ebx, null
	jne _lib_arb_no_null
	jmp _lib_arb_fin
_lib_arb_no_null:
	mov esi, [ebx+offset_izq]
	cmp esi, null
	je _lib_arb_ver_der
	push esi
	call _liberar_arbol	; liberamos recursivamente el arb. izq
	add esp,4
_lib_arb_ver_der:
	mov esi, [ebx+offset_der]
	cmp esi, null
	je _lib_arb_nodo_prin
	push esi
	call _liberar_arbol	; liberamos recursivamente el arb. der
	add esp,4
_lib_arb_nodo_prin:
	push ebx
	call free		; liberamos al nodo principal
	add esp,4
_lib_arb_fin:
	pop edi
	pop esi
	pop ebx
	leave
	ret	

